home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 23 / Amiga Format AFCD23 (Feb 1998, Issue 107).iso / -in_the_mag- / emulation / consoles / vision-8 / sources / amiga.c next >
C/C++ Source or Header  |  1997-12-12  |  21KB  |  887 lines

  1. /** Vision8: CHIP8 emulator *************************************************/
  2. /**                                                                        **/
  3. /**                                Amiga.c                                 **/
  4. /**                                                                        **/
  5. /** This file contains the Amiga implementation                            **/
  6. /**                                                                        **/
  7. /** Copyright (C) Lars Malmborg (glue@df.lth.se) 1997                      **/
  8. /**     You are not allowed to distribute this software commercially       **/
  9. /**     Please, notify me, if you make any changes to this file            **/
  10. /****************************************************************************/
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15.  
  16. /* Amiga includes */
  17. #include <proto/exec.h>
  18. #include <proto/dos.h>
  19. #include <proto/intuition.h>
  20. #include <proto/graphics.h>
  21. #include <proto/asl.h>
  22. #include <dos/rdargs.h>
  23. #include <exec/memory.h>
  24. #include <devices/audio.h>
  25.  
  26. #include "CHIP8.h"
  27.  
  28. /* Amiga RawKeys */
  29. #define KEY_ESC (0x45)
  30. #define KEY_F1 (0x50)
  31. #define KEY_HELP (0x5F)
  32.  
  33. #define KEY_1 (0x01)
  34. #define KEY_2 (0x02)
  35. #define KEY_3 (0x03)
  36. #define KEY_4 (0x04)
  37. #define KEY_Q (0x10)
  38. #define KEY_W (0x11)
  39. #define KEY_E (0x12)
  40. #define KEY_R (0x13)
  41. #define KEY_A (0x20)
  42. #define KEY_S (0x21)
  43. #define KEY_D (0x22)
  44. #define KEY_F (0x23)
  45. #define KEY_Z (0x31)
  46. #define KEY_X (0x32)
  47. #define KEY_C (0x33)
  48. #define KEY_V (0x34)
  49.  
  50. #define KEY_9 (0x09)
  51. #define KEY_0 (0x0A)
  52. #define KEY_MINUS (0x0B)
  53. #define KEY_EQUAL (0x0C)
  54. #define KEY_I (0x17)
  55. #define KEY_O (0x18)
  56. #define KEY_P (0x19)
  57. #define KEY_LBRACK (0x1A)
  58. #define KEY_J (0x26)
  59. #define KEY_K (0x27)
  60. #define KEY_L (0x28)
  61. #define KEY_SEMICOL (0x29)
  62. #define KEY_N (0x36)
  63. #define KEY_M (0x37)
  64. #define KEY_COMMA (0x38)
  65. #define KEY_PERIOD (0x39)
  66.  
  67. #define WIDTH   256
  68. #define HEIGHT  128
  69.  
  70. #define FREQUENCY 440        /* Frequency of the tone desired */
  71. #define DURATION 3            /* Duration in seconds */
  72. #define CLOCK 3546895        /* Clock constant, 3546895 for PAL */
  73. #define SAMPLES 2                /* Number of sample bytes */
  74. #define SAMPLECYCLES 1    /* Number of cycles in the sample */
  75.  
  76. #define PERIOD CLOCK*SAMPLECYCLES/(SAMPLES*FREQUENCY)
  77. #define CYCLES 0                /* Infinite loop (FREQUENCY*DURATION/SAMPLECYCLES) */
  78.  
  79. char *Title = "Vision-8 Amiga 1.0";
  80.  
  81. char *AmigaVersion="$VER: Vision-8 Amiga 1.0 "__AMIGADATE__;
  82.  
  83. char ReqText[]=    "Vision-8: Portable CHIP8 emulator\n"
  84.                                 "© 1997 by Marcel de Kogel\n"
  85.                                 "Amiga port 1.0 by Lars Malmborg\n";
  86.  
  87. struct EasyStruct HelpReq =
  88. {
  89.     sizeof(struct EasyStruct),
  90.     0,
  91.     "Vision-8 Help",
  92.     ReqText,
  93.     "OK"
  94. };
  95.  
  96. char *HelpText=    "Vision-8: Portable CHIP8 emulator\n"
  97.                                 "© 1997 by Marcel de Kogel\n"
  98.                                 "Amiga port 1.0 by Lars Malmborg\n"
  99.                                 "\n"
  100.                                 "Usage: v8 <filename> [options]\n"
  101.                                 "Available options are:\n"
  102.                                 " Verbose               - Print verbose information\n"
  103. #ifdef DEBUG
  104.                                 " Trap <pc> (hex)       - Trap execution when PC reaches address <pc> [000]\n"
  105. #endif
  106.                                 " UpdatePeriod <value>  - Select number of interrupts per screen update [1]\n"
  107.                                 " InstrPeriod <value>   - Select number of opcodes per interrupt [15]\n"
  108.                                 " NoSync                - Disable synchronisation of emulation\n"
  109.                                 " ScaleUp               - Double window size\n"
  110.                                 " Borderless            - Use a borderless window\n"
  111.                                 " PublicScreen <screen> - Open windows on a (public) screen\n"
  112.                                 " NoBuzzer              - Disable sound emulation\n"
  113.                                 " Help                  - Print this help page\n";
  114.  
  115.  
  116. struct Screen *scr=NULL;
  117. struct Window *win=NULL;
  118. struct RastPort *rp=NULL;
  119.  
  120. struct RastPort temprp;
  121.  
  122. LONG White=-1,Black=-1; /* White and black palette numbers */
  123.  
  124. BOOL ScaleUp;
  125. BOOL Verbose;
  126. BOOL Borderless;
  127. STRPTR PubScreen;
  128. int UpdatePeriod=1; /* Number of interrupts per screen update */
  129. BOOL Sync=TRUE; /* If 0, do not sync emulation with TOF */
  130.  
  131. BOOL Sound=TRUE;
  132.  
  133. STRPTR ReqFile(void);
  134.  
  135. UBYTE whichannel[]={1,2,4,8};
  136.  
  137. struct IOAudio AudioIO; /* Pointer to the I/O block for I/O commands */
  138. struct MsgPort *AudioMP=NULL; /* Pointer to a port so the device can reply */
  139. BYTE device=-1;
  140.  
  141. __chip static BYTE waveptr[SAMPLES]={127,-127};
  142.  
  143. /****************************************************************************/
  144. /* Turn sound on                                                            */
  145. /****************************************************************************/
  146. void chip8_sound_on (void)
  147. {
  148.     if(Sound)
  149.     {
  150.         AudioIO.ioa_Request.io_Message.mn_ReplyPort = AudioMP;
  151.         AudioIO.ioa_Request.io_Command              = CMD_WRITE;
  152.         AudioIO.ioa_Request.io_Flags                = ADIOF_PERVOL;
  153.         AudioIO.ioa_Data                            = (BYTE *)&waveptr;
  154.         AudioIO.ioa_Length                          = SAMPLES;
  155.         AudioIO.ioa_Period                          = PERIOD;
  156.         AudioIO.ioa_Volume                          = 64;
  157.         AudioIO.ioa_Cycles                          = CYCLES;
  158.  
  159.         BeginIO((struct IORequest *) &AudioIO );
  160.     }
  161. }
  162.  
  163. /****************************************************************************/
  164. /* Turn sound off                                                           */
  165. /****************************************************************************/
  166. void chip8_sound_off (void)
  167. {
  168.     if(Sound)
  169.     {
  170.         AudioIO.ioa_Request.io_Message.mn_ReplyPort = AudioMP;
  171.         AudioIO.ioa_Request.io_Command              = CMD_FLUSH;
  172.         AudioIO.ioa_Request.io_Flags                = NULL;
  173.  
  174.         BeginIO((struct IORequest *) &AudioIO );
  175.     }
  176. }
  177.  
  178. /****************************************************************************/
  179. /* Defines which key values represents CHIP8 equivalents                    */
  180. /****************************************************************************/
  181. /*
  182.  * Most of the original CHIP8 games are programmed for a keyboard with the
  183.  * following layout:
  184.  * 1 2 3 C
  185.  * 4 5 6 D
  186.  * 7 8 9 E
  187.  * A 0 B F
  188.  * This is emulated as follows (Physical location of keys is for US keymap):
  189.  * 1 2 3 4
  190.  * q w e r
  191.  * a s d f
  192.  * z x c v
  193.  * and:
  194.  * 9 0 - =
  195.  * i o p [
  196.  * j k l ;
  197.  * n m , .
  198.  */
  199. #define C8_0 13
  200. #define C8_1 0
  201. #define C8_2 1
  202. #define C8_3 2
  203. #define C8_4 4
  204. #define C8_5 5
  205. #define C8_6 6
  206. #define C8_7 8
  207. #define C8_8 9
  208. #define C8_9 10
  209. #define C8_A 12
  210. #define C8_B 14
  211. #define C8_C 3
  212. #define C8_D 7
  213. #define C8_E 11
  214. #define C8_F 15
  215.  
  216. /****************************************************************************/
  217. /* Update the display                                                       */
  218. /****************************************************************************/
  219. static void UpdateDisplay(void)
  220. {
  221.     UBYTE drawarray[2*WIDTH];
  222.  
  223.     register UBYTE *p;
  224.     register byte *q;
  225.     int i,j;
  226.  
  227.     register UBYTE b;
  228.     register UBYTE w;
  229.  
  230.     b=Black;
  231.     w=White;
  232.   q=chip8_display;
  233.  
  234.     if(ScaleUp)
  235.     {
  236.         for (i=0;i<32;i++)
  237.         {
  238.             p=(UBYTE *) drawarray;
  239.             for (j=0;j<64;j++)
  240.             {
  241.                 p[0]=p[1]=p[2]=p[3]=p[4]=p[5]=p[6]=p[7]=(*q)?w:b;
  242.                 q++;
  243.                 p+=8;
  244.             }
  245.             WritePixelLine8(rp,win->BorderLeft,win->BorderTop+i*8+0,
  246.                 2*WIDTH,(UBYTE*)drawarray,&temprp);
  247.             ClipBlit(rp,win->BorderLeft,win->BorderTop+i*8+0,
  248.                 rp,win->BorderLeft,win->BorderTop+i*8+1,
  249.                 2*WIDTH,1,0x0c0);
  250.             ClipBlit(rp,win->BorderLeft,win->BorderTop+i*8+0,
  251.                 rp,win->BorderLeft,win->BorderTop+i*8+2,
  252.                 2*WIDTH,2,0x0c0);
  253.             ClipBlit(rp,win->BorderLeft,win->BorderTop+i*8+0,
  254.                 rp,win->BorderLeft,win->BorderTop+i*8+4,
  255.                 2*WIDTH,4,0x0c0);
  256.         }
  257.     }
  258.     else
  259.     {
  260.         for (i=0;i<32;i++)
  261.         {
  262.             p=(UBYTE *) drawarray;
  263.             for (j=0;j<64;j++)
  264.             {
  265.                 p[0]=p[1]=p[2]=p[3]=(*q)?w:b;
  266.                 q++;
  267.                 p+=4;
  268.             }
  269.             WritePixelLine8(rp,win->BorderLeft,win->BorderTop+i*4+0,
  270.                 WIDTH,(UBYTE*)drawarray,&temprp);
  271.             ClipBlit(rp,win->BorderLeft,win->BorderTop+i*4+0,
  272.                 rp,win->BorderLeft,win->BorderTop+i*4+1,
  273.                 WIDTH,1,0x0c0);
  274.             ClipBlit(rp,win->BorderLeft,win->BorderTop+i*4+0,
  275.                 rp,win->BorderLeft,win->BorderTop+i*4+2,
  276.                 WIDTH,2,0x0c0);
  277.         }
  278.     }
  279. }
  280.  
  281. byte chip8_keys_left[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  282. byte chip8_keys_right[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  283.  
  284. /****************************************************************************/
  285. /* Update keyboard and display, sync emulation with TOF clock               */
  286. /****************************************************************************/
  287. void chip8_interrupt(void)
  288. {
  289.     static LONG UpdateCount=1;
  290.     struct IntuiMessage *imsg;
  291.     ULONG imsg_Class;
  292.     UWORD Code;
  293.     int i;
  294.  
  295.     while(imsg = (struct IntuiMessage*)GetMsg(win->UserPort))
  296.     {
  297.         imsg_Class = imsg->Class;
  298.         Code  = imsg->Code;
  299.         ReplyMsg((struct Message*)imsg);
  300.         switch(imsg_Class)
  301.         {
  302.             case IDCMP_CLOSEWINDOW:
  303.                 chip8_running=0;
  304.                 break;
  305.             case IDCMP_RAWKEY:
  306.                 if(Code & 0x80)
  307.                 {
  308.                     switch(Code & 0x7f)
  309.                     {
  310.                         case KEY_ESC:
  311.                             chip8_running=0;
  312.                             break;
  313.                         case KEY_F1:
  314.                             chip8_reset();
  315.                             break;
  316.                         case KEY_HELP:
  317.                             EasyRequestArgs(win,&HelpReq,NULL,NULL);
  318.                             break;
  319.                         /* Left keys */
  320.                         case KEY_1:
  321.                             chip8_keys_left[C8_1]=0;
  322.                             break;
  323.                         case KEY_2:
  324.                             chip8_keys_left[C8_2]=0;
  325.                             break;
  326.                         case KEY_3:
  327.                             chip8_keys_left[C8_3]=0;
  328.                             break;
  329.                         case KEY_4:
  330.                             chip8_keys_left[C8_C]=0;
  331.                             break;
  332.                         case KEY_Q:
  333.                             chip8_keys_left[C8_4]=0;
  334.                             break;
  335.                         case KEY_W:
  336.                             chip8_keys_left[C8_5]=0;
  337.                             break;
  338.                         case KEY_E:
  339.                             chip8_keys_left[C8_6]=0;
  340.                             break;
  341.                         case KEY_R:
  342.                             chip8_keys_left[C8_D]=0;
  343.                             break;
  344.                         case KEY_A:
  345.                             chip8_keys_left[C8_7]=0;
  346.                             break;
  347.                         case KEY_S:
  348.                             chip8_keys_left[C8_8]=0;
  349.                             break;
  350.                         case KEY_D:
  351.                             chip8_keys_left[C8_9]=0;
  352.                             break;
  353.                         case KEY_F:
  354.                             chip8_keys_left[C8_E]=0;
  355.                             break;
  356.                         case KEY_Z:
  357.                             chip8_keys_left[C8_A]=0;
  358.                             break;
  359.                         case KEY_X:
  360.                             chip8_keys_left[C8_0]=0;
  361.                             break;
  362.                         case KEY_C:
  363.                             chip8_keys_left[C8_B]=0;
  364.                             break;
  365.                         case KEY_V:
  366.                             chip8_keys_left[C8_F]=0;
  367.                             break;
  368.  
  369.                         /* Right keys */
  370.                         case KEY_9:
  371.                             chip8_keys_right[C8_1]=0;
  372.                             break;
  373.                         case KEY_0:
  374.                             chip8_keys_right[C8_2]=0;
  375.                             break;
  376.                         case KEY_MINUS:
  377.                             chip8_keys_right[C8_3]=0;
  378.                             break;
  379.                         case KEY_EQUAL:
  380.                             chip8_keys_right[C8_C]=0;
  381.                             break;
  382.                         case KEY_I:
  383.                             chip8_keys_right[C8_4]=0;
  384.                             break;
  385.                         case KEY_O:
  386.                             chip8_keys_right[C8_5]=0;
  387.                             break;
  388.                         case KEY_P:
  389.                             chip8_keys_right[C8_6]=0;
  390.                             break;
  391.                         case KEY_LBRACK:
  392.                             chip8_keys_right[C8_D]=0;
  393.                             break;
  394.                         case KEY_J:
  395.                             chip8_keys_right[C8_7]=0;
  396.                             break;
  397.                         case KEY_K:
  398.                             chip8_keys_right[C8_8]=0;
  399.                             break;
  400.                         case KEY_L:
  401.                             chip8_keys_right[C8_9]=0;
  402.                             break;
  403.                         case KEY_SEMICOL:
  404.                             chip8_keys_right[C8_E]=0;
  405.                             break;
  406.                         case KEY_N:
  407.                             chip8_keys_right[C8_A]=0;
  408.                             break;
  409.                         case KEY_M:
  410.                             chip8_keys_right[C8_0]=0;
  411.                             break;
  412.                         case KEY_COMMA:
  413.                             chip8_keys_right[C8_B]=0;
  414.                             break;
  415.                         case KEY_PERIOD:
  416.                             chip8_keys_right[C8_F]=0;
  417.                             break;
  418.                         default:
  419.                             break;
  420.                     }
  421.                 }
  422.                 else
  423.                 {
  424.                     switch(Code)
  425.                     {
  426.                         /* Left keys */
  427.                         case KEY_1:
  428.                             chip8_keys_left[C8_1]=1;
  429.                             break;
  430.                         case KEY_2:
  431.                             chip8_keys_left[C8_2]=1;
  432.                             break;
  433.                         case KEY_3:
  434.                             chip8_keys_left[C8_3]=1;
  435.                             break;
  436.                         case KEY_4:
  437.                             chip8_keys_left[C8_C]=1;
  438.                             break;
  439.                         case KEY_Q:
  440.                             chip8_keys_left[C8_4]=1;
  441.                             break;
  442.                         case KEY_W:
  443.                             chip8_keys_left[C8_5]=1;
  444.                             break;
  445.                         case KEY_E:
  446.                             chip8_keys_left[C8_6]=1;
  447.                             break;
  448.                         case KEY_R:
  449.                             chip8_keys_left[C8_D]=1;
  450.                             break;
  451.                         case KEY_A:
  452.                             chip8_keys_left[C8_7]=1;
  453.                             break;
  454.                         case KEY_S:
  455.                             chip8_keys_left[C8_8]=1;
  456.                             break;
  457.                         case KEY_D:
  458.                             chip8_keys_left[C8_9]=1;
  459.                             break;
  460.                         case KEY_F:
  461.                             chip8_keys_left[C8_E]=1;
  462.                             break;
  463.                         case KEY_Z:
  464.                             chip8_keys_left[C8_A]=1;
  465.                             break;
  466.                         case KEY_X:
  467.                             chip8_keys_left[C8_0]=1;
  468.                             break;
  469.                         case KEY_C:
  470.                             chip8_keys_left[C8_B]=1;
  471.                             break;
  472.                         case KEY_V:
  473.                             chip8_keys_left[C8_F]=1;
  474.                             break;
  475.  
  476.                         /* Right keys */
  477.                         case KEY_9:
  478.                             chip8_keys_right[C8_1]=1;
  479.                             break;
  480.                         case KEY_0:
  481.                             chip8_keys_right[C8_2]=1;
  482.                             break;
  483.                         case KEY_MINUS:
  484.                             chip8_keys_right[C8_3]=1;
  485.                             break;
  486.                         case KEY_EQUAL:
  487.                             chip8_keys_right[C8_C]=1;
  488.                             break;
  489.                         case KEY_I:
  490.                             chip8_keys_right[C8_4]=1;
  491.                             break;
  492.                         case KEY_O:
  493.                             chip8_keys_right[C8_5]=1;
  494.                             break;
  495.                         case KEY_P:
  496.                             chip8_keys_right[C8_6]=1;
  497.                             break;
  498.                         case KEY_LBRACK:
  499.                             chip8_keys_right[C8_D]=1;
  500.                             break;
  501.                         case KEY_J:
  502.                             chip8_keys_right[C8_7]=1;
  503.                             break;
  504.                         case KEY_K:
  505.                             chip8_keys_right[C8_8]=1;
  506.                             break;
  507.                         case KEY_L:
  508.                             chip8_keys_right[C8_9]=1;
  509.                             break;
  510.                         case KEY_SEMICOL:
  511.                             chip8_keys_right[C8_E]=1;
  512.                             break;
  513.                         case KEY_N:
  514.                             chip8_keys_right[C8_A]=1;
  515.                             break;
  516.                         case KEY_M:
  517.                             chip8_keys_right[C8_0]=1;
  518.                             break;
  519.                         case KEY_COMMA:
  520.                             chip8_keys_right[C8_B]=1;
  521.                             break;
  522.                         case KEY_PERIOD:
  523.                             chip8_keys_right[C8_F]=1;
  524.                             break;
  525.                         default:
  526.                             break;
  527.                     }
  528.                 }
  529.                 break;
  530.         }
  531.     }
  532.  
  533.     /* Merge pressed keys */
  534.     for(i=0;i<16;i++)
  535.         chip8_keys[i]=chip8_keys_left[i]|chip8_keys_right[i];
  536.  
  537.     if(Sync)
  538.     {
  539.         WaitTOF();
  540.     }
  541.  
  542.  if(!--UpdateCount)
  543.  {
  544.   UpdateCount=UpdatePeriod;
  545.     UpdateDisplay();
  546.  }
  547. }
  548.  
  549. /****************************************************************************/
  550. /** Deallocate all resources taken by InitMachine()                        **/
  551. /****************************************************************************/
  552. static void TrashMachine(void)
  553. {
  554.     if(Sound)
  555.     {
  556.         if(device==0)
  557.             CloseDevice((struct IORequest *)&AudioIO);
  558.         if(AudioMP)
  559.             DeletePort(AudioMP);
  560.     }
  561.  
  562.     if (temprp.BitMap)
  563.         FreeBitMap(temprp.BitMap);
  564.  
  565.     if(Black!=-1)
  566.     {
  567.         ReleasePen(scr->ViewPort.ColorMap,Black);
  568.     }
  569.  
  570.     if(White!=-1)
  571.     {
  572.         ReleasePen(scr->ViewPort.ColorMap,White);
  573.     }
  574.  
  575.     if (win)
  576.         CloseWindow(win);
  577. }
  578.  
  579. /****************************************************************************/
  580. /** Allocate resources needed by Amiga-dependent code                      **/
  581. /****************************************************************************/
  582. static int InitMachine(void)
  583. {
  584.     int scale;
  585.     if (ScaleUp)
  586.         scale=2;
  587.     else
  588.         scale=1;
  589.  
  590.     if (scr = LockPubScreen(PubScreen))
  591.     {
  592.         if(Borderless)
  593.         {
  594.             win = OpenWindowTags(NULL,
  595.                     WA_Left,(scr->Width - scale*(WIDTH))/2,
  596.                     WA_Top,(scr->Height - scale*HEIGHT)/2,
  597.                     WA_InnerWidth,scale*(WIDTH),
  598.                     WA_InnerHeight,scale*HEIGHT,
  599.                     WA_RMBTrap,TRUE,
  600.                     WA_Activate,TRUE,
  601.                     WA_IDCMP,IDCMP_RAWKEY|IDCMP_CLOSEWINDOW,
  602.                     WA_PubScreenName,PubScreen,
  603.                     WA_Flags,WFLG_BORDERLESS,
  604.                     TAG_END
  605.             );
  606.         }
  607.         else
  608.         {
  609.             win = OpenWindowTags(NULL,
  610.                     WA_Left,(scr->Width - scale*(WIDTH))/2,
  611.                     WA_Top,(scr->Height - scale*HEIGHT)/2,
  612.                     WA_InnerWidth,scale*(WIDTH),
  613.                     WA_InnerHeight,scale*HEIGHT,
  614.                     WA_Title,Title,
  615.                     WA_CloseGadget,TRUE,
  616.                     WA_DepthGadget,TRUE,
  617.                     WA_DragBar,TRUE,
  618.                     WA_SizeGadget,FALSE,
  619.                     WA_RMBTrap,TRUE,
  620.                     WA_Activate,TRUE,
  621.                     WA_IDCMP,IDCMP_RAWKEY|IDCMP_CLOSEWINDOW,
  622.                     WA_PubScreenName,PubScreen,
  623.                     TAG_END
  624.             );
  625.         }
  626.  
  627.         UnlockPubScreen(PubScreen,scr);
  628.  
  629.         if(win)
  630.         {
  631.             rp = win->RPort;
  632.  
  633.             Black = ObtainBestPenA(scr->ViewPort.ColorMap,0x00000000,0x00000000,0x00000000,NULL);
  634.             White = ObtainBestPenA(scr->ViewPort.ColorMap,0xff000000,0xff000000,0xff000000,NULL);
  635.  
  636.             CopyMem(rp,&temprp,sizeof(struct RastPort));
  637.             temprp.Layer=NULL;
  638.             if (!(temprp.BitMap=AllocBitMap(scale*(WIDTH),1,rp->BitMap->Depth,0,NULL)))
  639.             {
  640.                 fprintf(stderr,"Error allocating temporary rastport.\n");
  641.                 return(0);
  642.             }
  643.         }
  644.         else
  645.         {
  646.             fprintf(stderr,"Can't open window.\n");
  647.             return(0);
  648.         }
  649.     }
  650.     else
  651.     {
  652.         fprintf(stderr,"Screen not found.\n");
  653.         return(0);
  654.     }
  655.  
  656.     if(Sound)
  657.     {
  658.         if(!(AudioMP=CreatePort(0,0)))
  659.         {
  660.             fprintf(stderr,"Can't create message port for sound channel.\n");
  661.             return(0);
  662.         }
  663.         AudioIO.ioa_Request.io_Message.mn_ReplyPort   = AudioMP;
  664.         AudioIO.ioa_Request.io_Message.mn_Node.ln_Pri = 0;
  665.         AudioIO.ioa_Request.io_Command                = ADCMD_ALLOCATE;
  666.         AudioIO.ioa_AllocKey                          = 0;
  667.         AudioIO.ioa_Data                              = whichannel;
  668.         AudioIO.ioa_Length                            = sizeof(whichannel);
  669.  
  670.         if(device=OpenDevice("audio.device",0L,(struct IORequest *)&AudioIO,0L))
  671.         {
  672.             fprintf(stderr,"Can't allocate sound channel.\n");
  673.             return(0);
  674.         }
  675.     }
  676.  
  677.     return(1);
  678. }
  679.  
  680. #define OPT_PROGRAM ((STRPTR)(ArgPtrs[0]))
  681. #define OPT_VERBOSE ((BOOL)(ArgPtrs[1]))
  682. #define OPT_TRAP ((STRPTR)(ArgPtrs[2]))
  683. #define OPT_UP ((ULONG*)(ArgPtrs[3]))
  684. #define OPT_IP ((ULONG*)(ArgPtrs[4]))
  685. #define OPT_NOSYNC ((BOOL)(ArgPtrs[5]))
  686. #define OPT_SCALE ((BOOL)(ArgPtrs[6]))
  687. #define OPT_BORDER ((BOOL)(ArgPtrs[7]))
  688. #define OPT_PSCREEN ((STRPTR)(ArgPtrs[8]))
  689. #define OPT_NOSOUND ((BOOL)(ArgPtrs[9]))
  690. #define OPT_HELP ((BOOL)(ArgPtrs[10]))
  691.  
  692. /****************************************************************************/
  693. /* Parse command line options the Amiga way and start emulation             */
  694. /****************************************************************************/
  695. int main(void)
  696. {
  697.     LONG ArgPtrs[11]={0};
  698.     struct RDArgs *Args;
  699.     STRPTR FileNameBuf=NULL;
  700.     BPTR fh;
  701.  
  702.     chip8_iperiod=15;
  703.  
  704.   Verbose=FALSE;
  705.   UpdatePeriod=1;
  706.     Sync=TRUE;
  707.     ScaleUp=FALSE;
  708.     Borderless=FALSE;
  709.     PubScreen=NULL;
  710.     Sound=TRUE;
  711.  
  712.     if(Args = ReadArgs("Program,V=Verbose/S,T=Trap/K,UP=UpdatePeriod/K/N,IP=InstrPeriod/K/N,NS=NoSync/S,2=ScaleUp/S,B=Borderless/S,PS=PublicScreen/K,NB=NoBuzzer/S,Help/K/S",ArgPtrs,NULL))
  713.     {
  714.         if(OPT_PROGRAM)
  715.         {
  716.             if (FileNameBuf = AllocVec(strlen(OPT_PROGRAM)+1,MEMF_ANY|MEMF_CLEAR))
  717.                 strcpy(FileNameBuf,OPT_PROGRAM);
  718.         }
  719.  
  720.         if(OPT_VERBOSE)
  721.         {
  722.             Verbose = TRUE;
  723.         };
  724.  
  725.         if(OPT_TRAP)
  726.         {
  727.             sscanf(OPT_TRAP,"%hx",&chip8_trap);
  728.         };
  729.  
  730.         if(OPT_UP)
  731.         {
  732.             UpdatePeriod = (int)(*OPT_UP);
  733.         };
  734.  
  735.         if(OPT_IP)
  736.         {
  737.             chip8_iperiod = (int)(*OPT_IP);
  738.         };
  739.  
  740.         if(OPT_NOSYNC)
  741.         {
  742.             Sync = FALSE;
  743.         };
  744.  
  745.         if(OPT_SCALE)
  746.         {
  747.             ScaleUp = TRUE;
  748.         };
  749.  
  750.         if(OPT_BORDER)
  751.         {
  752.             Borderless = TRUE;
  753.         };
  754.  
  755.         if(OPT_PSCREEN)
  756.         {
  757.             if (PubScreen=AllocVec(strlen(OPT_PSCREEN)+1,MEMF_ANY|MEMF_CLEAR))
  758.                 strcpy(PubScreen,OPT_PSCREEN);
  759.         }
  760.  
  761.         if(OPT_NOSOUND)
  762.         {
  763.             Sound = FALSE;
  764.         };
  765.  
  766.         if(OPT_HELP)
  767.         {
  768.             puts(HelpText);
  769.             FreeArgs(Args);
  770.             if (FileNameBuf)
  771.                 FreeVec(FileNameBuf);
  772.             if (PubScreen)
  773.                 FreeVec(PubScreen);
  774.             return(0);
  775.         };
  776.  
  777.         FreeArgs(Args);
  778.  
  779.         if (!FileNameBuf)
  780.         {
  781.             if((FileNameBuf = ReqFile()) == NULL) exit(0);
  782.         }
  783.  
  784.         if(Verbose)
  785.             printf("Trap %03x, UpdatePeriod %d, InstrPeriod %d, %s, %s size, %s, PublicScreen \"%s\", %s\n",
  786.                 chip8_trap,
  787.                 UpdatePeriod,
  788.                 chip8_iperiod,
  789.                 Sync?"Synchronized":"Freerun",
  790.                 ScaleUp?"Double":"Normal",
  791.                 Borderless?"Borderless":"Normal window",
  792.                 PubScreen?(char*)PubScreen:"<Default>",
  793.                 Sound?"Buzzer":"Quiet");
  794.  
  795.         if(UpdatePeriod<=0)
  796.         {
  797.             fprintf(stderr,"Invalid UpdatePeriod.\n");
  798.             return(1);
  799.         }
  800.  
  801.         if(chip8_iperiod<=0)
  802.         {
  803.             fprintf(stderr,"Invalid InstrPeriod.\n");
  804.             return(1);
  805.         }
  806.  
  807.         if((chip8_trap<0)||(chip8_trap>=0x1000))
  808.         {
  809.             fprintf(stderr,"Invalid Trap.\n");
  810.             return(1);
  811.         }
  812.  
  813.         if(Verbose&&(chip8_trap<0x200))
  814.             fprintf(stderr,"Trap set outside user program.\n");
  815.  
  816.         if(Verbose)
  817.             printf("Opening CHIP8 program \"%s\".\n",FileNameBuf);
  818.  
  819.         if(fh=Open(FileNameBuf,MODE_OLDFILE))
  820.         {
  821.             int len;
  822.             len=Read(fh,chip8_mem+0x200,4096-0x200);
  823.             if(Verbose)
  824.                 printf("%d bytes read.\n",len);
  825.             Close(fh);
  826.         }
  827.         else
  828.         {
  829.             fprintf(stderr,"File \"%s\" not found.\n",FileNameBuf);
  830.             if (FileNameBuf)
  831.                 FreeVec(FileNameBuf);
  832.             if (PubScreen)
  833.                 FreeVec(PubScreen);
  834.             return(1);
  835.         }
  836.  
  837.         if (!InitMachine())
  838.         {
  839.             TrashMachine();
  840.             if (FileNameBuf)
  841.                 FreeVec(FileNameBuf);
  842.             if (PubScreen)
  843.                 FreeVec(PubScreen);
  844.             return(1);
  845.         }
  846.         chip8();
  847.         TrashMachine();
  848.         if (FileNameBuf)
  849.             FreeVec(FileNameBuf);
  850.         if (PubScreen)
  851.             FreeVec(PubScreen);
  852.       return(0);
  853.     }
  854.     else
  855.     {
  856.         fprintf(stderr,"Couldn't parse options. Uh, this is really serious!\n");
  857.         return(1);
  858.     }
  859. }
  860.  
  861. STRPTR ReqFile(void)
  862. {
  863.     struct FileRequester *AslReq;
  864.     STRPTR File=NULL;
  865.     WORD namelen;
  866.  
  867.     if(AslReq = (struct FileRequester*)AllocAslRequestTags(ASL_FileRequest,
  868.             ASLFR_PubScreenName,PubScreen,
  869.             ASLFR_TitleText,"Select a program...",
  870.             ASLFR_PositiveText,"Run",
  871.             ASLFR_RejectIcons,TRUE,
  872.             TAG_END))
  873.     {
  874.         if(AslRequest(AslReq,NULL))
  875.         {
  876.             namelen = strlen(AslReq->fr_File) + strlen(AslReq->fr_Drawer) + 2;
  877.             if(File = AllocVec(namelen,MEMF_ANY | MEMF_CLEAR))
  878.             {
  879.                 strcpy(File,AslReq->fr_Drawer);
  880.                 AddPart(File,AslReq->fr_File,namelen);
  881.             }
  882.         }
  883.         FreeAslRequest((APTR)AslReq);
  884.     }
  885.     return File;
  886. }
  887.